﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime.InteropServices.Automation;
using System.Reflection;
using SL8.SL.Data.Mapping;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.ComponentModel;
using System.Diagnostics;

namespace SL8.SL.Data.Sql
{
    public class LocalMSAccessSqlProvider : ISqlProvider
    {
        private object lockObj = new Object();
        private static System.Threading.SynchronizationContext _synchronizationContext;
        public static SynchronizationContext SynchronizationContext
        {
            get
            {
                return LocalMSAccessSqlProvider._synchronizationContext;
            }

            private set
            {
                LocalMSAccessSqlProvider._synchronizationContext = value;
            }
        }

        public string DataBasePath { get; set; }

        // 缓存，避免每次都反射读取
        private Dictionary<Type, Dictionary<string, PropertyInfo>> ColumnCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

        static LocalMSAccessSqlProvider()
        {
            LocalMSAccessSqlProvider.SynchronizationContext = SynchronizationContext.Current;
        }

        public void Excute<T>(string sql, Action<Result<T>> onComplete) where T : new()
        {
            if (onComplete != null)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
                    {
                        lock (this.lockObj)
                        {
                            System.Diagnostics.Debug.WriteLine(string.Format("sql:{0}", sql));

                            dynamic conn = AutomationFactory.CreateObject("ADODB.Connection");
                            dynamic recordSet = AutomationFactory.CreateObject("ADODB.RecordSet");

                            try
                            {
                                conn.Open("Driver={Microsoft Access Driver (*.mdb)}; DBQ=" + DataBasePath);

                                // 1 查询 3 可写
                                recordSet.Open(sql, conn, 1, 3);

                                Type elementType = typeof(T);
                                Dictionary<string, PropertyInfo> dictColumn = null;

                                if (!this.ColumnCache.ContainsKey(elementType))
                                {
                                    PropertyInfo[] propertiesTemp = elementType.GetProperties();
                                    dictColumn = new Dictionary<string, PropertyInfo>();

                                    foreach (var property in propertiesTemp)
                                    {
                                        object[] atts = property.GetCustomAttributes(typeof(ColumnAttribute), false);
                                        if (atts.Length == 1)
                                        {
                                            dictColumn.Add(((ColumnAttribute)atts[0]).Name, property);
                                        }
                                    }

                                    this.ColumnCache.Add(elementType, dictColumn);
                                }
                                else
                                {
                                    dictColumn = this.ColumnCache[elementType];
                                }

                                List<T> list = new List<T>();

                                int j = 1;
                                if (recordSet.State != 0)
                                {
                                    while (!recordSet.EOF)
                                    {

                                        T t = new T();
                                        int fieldCount = recordSet.Fields.Count;

                                        for (int i = 0; i < fieldCount; i++)
                                        {
                                            if (dictColumn.ContainsKey(recordSet.Fields[i].Name))
                                            {
                                                PropertyInfo property = dictColumn[recordSet.Fields[i].Name];
                                                if (property != null)
                                                {
                                                    string value = recordSet.Fields[i].Value.ToString();
                                                    System.Diagnostics.Debug.WriteLine(string.Format("column name:{0}  column vlaue:{1}", property.Name, value));
                                                    Type propertyType = Nullable.GetUnderlyingType(property.PropertyType);

                                                    if (propertyType == null)
                                                    {
                                                        propertyType = property.PropertyType;
                                                    }

                                                    try
                                                    {
                                                        property.SetValue(t, Convert.ChangeType(value, propertyType, null), null);
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        System.Diagnostics.Debug.WriteLine(string.Format("ChangeType:{0} ", ex));
                                                        System.Diagnostics.Debug.WriteLine(string.Format("Value:{0} ", value));
                                                    }
                                                }
                                            }
                                        }

                                        list.Add(t);
                                        recordSet.MoveNext();
                                        j++;
                                    }
                                }

                                LocalMSAccessSqlProvider.SynchronizationContext.Send((o) =>
                                {
                                    onComplete(new Result<T>(list.Count, list));
                                }, null);
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine(ex);
                                LocalMSAccessSqlProvider.SynchronizationContext.Send((o) =>
                                {
                                    if (onComplete != null)
                                    {
                                        onComplete(new Result<T>(0, null, ex));
                                    }
                                }, null);

                            }
                            finally
                            {
                                if (recordSet.State != 0)
                                {
                                    recordSet.Close();
                                }

                                if (conn.State != 0)
                                {
                                    conn.Close();
                                }
                            }
                        }
                    }));
            }
        }
    }
}
